package dao

import (
	"database/sql"
	gorm_v2 "gitee.com/youbeiwuhuan/gin-practice/fizz-gorm2/tools/gormv2"
	"gitee.com/youbeiwuhuan/gin-practice/fizz-gorm2/tools/reflects"
	"gorm.io/gorm"
	"reflect"
)

const (
	// 分页器时，默认允许最大的记录数
	MaxLimit = 1000
)

// BaseDao 初始化 gorm 实例的其他字段
type BaseDao[T any] struct {
	db        *gorm.DB
	model     T
	modelType reflect.Type
}

func NewBaseDao[T any](db0 *gorm.DB, model0 T) *BaseDao[T] {
	if !reflects.IsStruct(model0) {
		panic("model0 is not a struct !")
	}

	return &BaseDao[T]{
		db:        db0,
		model:     model0,
		modelType: reflect.TypeOf(&model0),
	}
}

func (dao *BaseDao[T]) insert(entityData T) int64 {
	tx := dao.db.Save(&entityData)
	return tx.RowsAffected
}

func (dao *BaseDao[T]) GetById(id int64) T {
	u := dao.model
	// 根据主键获取记录（仅适用于整型主键）
	dao.db.First(&u, id)

	return u
}

func (dao *BaseDao[T]) UpdateById(entityData T) int64 {
	tx := dao.db.Model(&dao.model).Updates(entityData)
	return tx.RowsAffected
}

func (dao *BaseDao[T]) DeleteById(id int64) int64 {
	u := gorm_v2.CreateEntityAndSetId(dao.model, id)
	/// 删除一条已有的记录（email 的主键值为 10）
	tx := dao.db.Delete(&u)
	// DELETE from emails where id=10;

	return tx.RowsAffected
}

func (dao *BaseDao[T]) GetDb() *gorm.DB {
	return dao.db
}

// BeginTx 开启事务：开启事务之后，必须使用开启事务返回的*gorm.DB, 而不是开启事务时使用*gorm.DB
func (dao *BaseDao[T]) BeginTx(opts ...*sql.TxOptions) *gorm.DB {
	return dao.db.Begin(opts...)
}

// RollbackTx 事务回滚
func (dao *BaseDao[T]) RollbackTx(dbTx *gorm.DB) {
	dbTx.Rollback()
}

// CommitTx 事务提交
func (dao *BaseDao[T]) CommitTx(dbTx *gorm.DB) {
	dbTx.Rollback()
}

// execTx 执行事务
func (dao *BaseDao[T]) execTx(txFn func(*gorm.DB) (error, interface{}), opts ...*sql.TxOptions) (error, interface{}) {
	dbTx := dao.db.Begin(opts...)

	defer func() {
		if r := recover(); r != nil {
			//fmt.Println("Recovered from:", r)
			dbTx.Rollback()
			panic(r)
		}
	}()

	err, data := txFn(dbTx)
	if err != nil {
		dbTx.Rollback()
	} else {
		dbTx.Commit()
	}

	return err, data
}
